package http

import (
	"invitation/internal/application"
	"invitation/internal/http/middleware"
	"invitation/internal/http/routes"
	"invitation/internal/http/schema"
	"invitation/internal/http/utils"

	"github.com/gofiber/contrib/fiberzerolog"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/recover"

	"github.com/rs/zerolog/log"
)

func API(application *application.Application) (*fiber.App, error) {
	fiberCfg := fiber.Config{
		BodyLimit:             1024 * 1024,
		DisableStartupMessage: true,
	}
	router := fiber.New(fiberCfg)
	router.Hooks().OnListen(func(listenData fiber.ListenData) error {
		scheme := "http"
		if listenData.TLS {
			scheme = "https"
		}
		log.Info().Str("endpoint", scheme+"://"+listenData.Host+":"+listenData.Port).Msg("Invitation API is listening! Please connect to the endpoint for API documentation.")
		return nil
	})
	logger := log.Logger
	router.Use(fiberzerolog.New(fiberzerolog.Config{
		Logger: &logger,
	}))
	if !application.ApplicationConfig().Debug {
		router.Use(recover.New())
	}
	allowHeaders := "*"
	if application.ApplicationConfig().CORS {
		router.Use(cors.New(cors.Config{
			AllowOrigins:     cors.ConfigDefault.AllowOrigins,
			AllowMethods:     cors.ConfigDefault.AllowMethods,
			AllowHeaders:     allowHeaders,
			AllowCredentials: cors.ConfigDefault.AllowCredentials,
		}))
	}

	re := middleware.NewRequestExtractor(application.RepoManager(), application.ApplicationConfig())
	routes.RegisterAdminRoutes(router, application, re)
	routes.RegisterInvitationRoutes(router, application, re)
	router.Use(notFoundHandler)
	return router, nil
}

func notFoundHandler(c *fiber.Ctx) error {
	// Check if the request accepts JSON
	if string(c.Context().Request.Header.ContentType()) == "application/json" || len(c.Accepts("html")) == 0 {
		// The client expects a JSON response
		return c.Status(fiber.StatusNotFound).JSON(schema.ErrorResponse{
			Error: &schema.APIError{Message: "Resource not found", Code: fiber.StatusNotFound},
		})
	} else {
		// The client expects an HTML response
		return c.Status(fiber.StatusNotFound).Render("views/404", fiber.Map{
			"BaseURL": utils.BaseURL(c),
		})
	}
}
